/*
 * @module zf
 * @author zfkun@msn.com
 */
;(function(base, version) {

    base = base || window;

    var Z = base.ZF = base.ZF || {},
        startTime = +new Date,
        guidp = 'z',
        guidx = 0;

    function mix(/*[deep,]to, from1, from2, ...*/) {
         var from, name, src, copy, copyIsArray, clone,
            to = arguments[0] || {},
            i = 1,
            length = arguments.length,
            deep = false;

        // Handle a deep copy situation
        if (typeof to === "boolean") {
            deep = to;
            to = arguments[1] || {};
            // skip the boolean and the to
            i = 2;
        }

        // Handle case when to is a string or something (possible in deep copy)
        if ((typeof to !== "object") && (typeof to !== "function")) {
            to = {};
        }

        for (; i < length; i++) {
            // Only deal with non-null/undefined values
            if ((from = arguments[i]) != null) {
                // Extend the base object
                for (name in from) {
                    src = to[name];
                    copy = from[name];

                    // Prevent never-ending loop
                    if (to === copy) {
                        continue;
                    }

                    // Recurse if we're merging plain objects or arrays
                    if (deep && copy && (Z.Lang.isPlainObject(copy) || (copyIsArray = Z.Lang.isArray(copy)))) {
                        if (copyIsArray) {
                            copyIsArray = false;
                            clone = Z.Lang.toArray(src);
                        } else {
                            clone = src && Z.Lang.isPlainObject(src) ? src : {};
                        }

                        // Never move original objects, clone them
                        to[name] = mix(deep, clone, copy);

                    // Don't bring in undefined values
                    } else if (copy !== undefined) {
                        to[name] = copy;
                    }
                }
            }
        }

        // Return the modified object
        return to;
    };


    mix(Z, {

        _init : function() {
            var self = this;
            
            // Config
            self.Config = self.Config || {

                // module js file name maker
                //moduleJsNamer : function(name) { return name + '-m.js' },

                // module css file name maker
                //moduleCssNamer : function(name) { return name + '-m.css' },

                // debug mode for dev
                debug : /debug\=1/.test(location.search || ''),
                
                // loader's timeout
                loadTimeout : 10

            };
            
            // Env
            self.Env = self.Env || {

                // winow alias
                win : window,
                
                // document alias
                doc : document,
                
                // attached modules
                mods : {},
                
                // queue for loader
                __LOAD_QUEUE : []
            
            };
            
            // current version
            self.version = self.version || version;
        },

        emptyFn : function() {},

        mix : mix,

        merge : function(/*from1, from2, ...*/) {
            return mix.apply(mix, [true, {}].concat([].slice.call(arguments)));
        },
        
        extend : function(/*to, from1, from2, ...*/) {
            var l = arguments.length;
            
            // extend ZF itself if only one argument is passed
            if (l == 1) {
                return mix.call(mix, Z, arguments[0]);
            }
            
            return mix.apply(mix, arguments);
        },
        
        /*
         * Class Creater
         */
        create : function(fn, superClass, staticMethods) {
            var L = Z.Lang,
                PT = 'prototype',
                CONSTRUCT = 'construct',
                constructMethod = fn && fn[CONSTRUCT],
                newClass = constructMethod ? function() {
                        constructMethod.apply(this, arguments);
                        return this;
                    } : (fn && fn.init ? function() {
                        return this.init.apply(this, arguments);
                    } : function(){ return this; });

            // static methods
            if (L.isPlainObject(staticMethods)) {
                mix(newClass, staticMethods);
            }

            if (!fn) {
                return newClass;
            }

            if (constructMethod) {
                fn[CONSTRUCT] = null;
                delete fn[CONSTRUCT];
            }

            if (L.isPlainObject(fn)) {
                // class methods only
                mix(newClass[PT], fn);
            } else if (L.isFunction(fn)) {
                // class by function
                if (superClass && L.isFunction(superClass)) {
                    // access methods of parent
                    newClass.superClass = superClass;

                    var subPros = newClass[PT],
                        spPros = superClass[PT];

                    // inheritance methods from parent
                    mix(subPros, spPros);
                    // extend methods of fn
                    mix(subPros, fn(spPros));

                    // allow sub access parent
                    //subPros.superClass = spPros;
                } else {
                    mix(newClass[PT], fn());
                }
                newClass.constructor = fn;
            }

            return newClass;
        },

        namespace : function(/*n1, n2, ..., root*/) {
            var args = arguments,
                i,
                j,
                l = args.length, m,
                isRoot = args[l - 1] === true,
                r,
                name;

            if (isRoot) {
                l--;
            }

            for (i = 0; i < l; i++) {
                name = args[i].split('.');
                r = isRoot ? base : this;
                for(j = (base[name[0]] === r ? 1 : 0), m = name.length; j < m; j++) {
                    r = r[name[j]] = r[name[j]] || {};
                }
            }

            return r;
        },
        
        now : function() {
            return +new Date();
        },
        
        guid : function(pre) {
            var id = guidp + (++guidx);
            return pre ? pre + id : id;
        },
        
        log : function(message, level) {
            var debugMode = this.Config.debug, loger;
            if (debugMode) {
                loger = base.console;
                if (loger) {
                    loger[loger[level] ? level : 'log'](message);
                }
            }
        },
        
        error : function(message) {
            if (this.Config.debug) {
                throw message;
            }
        }

    });

    Z.toString = function() {
        return 'ZF-' + version + '-' + startTime;
    }

    Z._init();

})(this, '1.0.0');
